package com.yx.changdao.generate.utils;

import com.yx.changdao.generate.main.GenerateMain;
import com.yx.changdao.generate.model.ColumnClass;
import com.yx.changdao.generate.model.CreateCodeParam;
import com.yx.changdao.generate.model.DataDictClass;
import com.yx.changdao.generate.model.DataDictParam;
import freemarker.template.Template;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description: <br/>
 * 生成器
 * <p>
 * <br/>
 * @Auther: zhangqi
 * @create 2019/11/22 9:37
 */
public class CodeGenerateUtils {


    /**
     * 数据库字段生成器
     */
    public static void generateDBDict(DataDictParam dataDictParam) throws Exception {
        Connection conn = MySQLTableComment.getMySQLConnection(dataDictParam.getURL(), dataDictParam.getUser(), dataDictParam.getPassword());
        // 获取数据字典
        List<Map<String, List<DataDictClass>>> dataDict = MySQLTableComment.getDataDict(conn);
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("tables", dataDict);
        new CodeGenerateUtils().generateDBDictFile(dataMap, dataDictParam);
        System.out.println("完成");
    }


    /**
     * 单表生产
     */
    public static void generateOneTable(CreateCodeParam createCodeParam) {
        String packageName = StringUtils.replace(StringUtils.replace(GenerateMain.class.getName(), ".generate.main.GenerateMain", ""), ".", "/");
        createCodeParam.setPackageName(StringUtils.replace(GenerateMain.class.getName(), ".generate.main.GenerateMain", ""));
        // 参数为空
        File directory = new File("");
        String courseFile = null;
        try {
            courseFile = directory.getCanonicalPath();
        } catch (IOException e) {

        }
        courseFile = new File(courseFile).getPath();
        String[] list = new File(courseFile).list();
        for (String s : list) {
            File file = new File(courseFile + "/" + s);
            if (file.isDirectory() && !s.startsWith(".") && !s.contains("generate")) {
                String module = StringUtils.substring(s, s.lastIndexOf("_") + 1);
                String path = file.getPath() + "/src/main/java/" + packageName + "/";
                new CodeGenerateUtils().generate(module, path);
            }

        }
        System.out.println("完成");
    }


    /**
     * 生成代码
     *
     * @throws Exception
     */
    public void generate(String moduleName, String basePath) {
        try {

            String tableName = CreateCodeParam.TABLE_NAME;
            Connection connection = MySQLTableComment.getMySQLConnection(CreateCodeParam.URL, CreateCodeParam.USER, CreateCodeParam.PASSWORD);
            DatabaseMetaData databaseMetaData = connection.getMetaData();

            List tables = MySQLTableComment.getAllTableName(connection);
            Map tablesComment = MySQLTableComment.getCommentByTableName(tables, connection);
            ResultSet resultSet = databaseMetaData.getColumns(null, "%", tableName, "%");

            ResultSet primaryKeys = databaseMetaData.getPrimaryKeys(null, null, tableName);

            // 主键的list 生成java实体时判断主键时使用
            List<String> primaryKeyslist = new ArrayList<>();
            while (primaryKeys.next()) {
                primaryKeyslist.add(primaryKeys.getString(4));
            }


            // 判断模块生成具体的java代码
            switch (moduleName) {
                // 通用模块
                case "common":
                    // 生成MybatisPlus的Mapper
                    this.generateMapperFile(basePath + "/common/mapper/", resultSet, tableName, String.valueOf(tablesComment.get(tableName)));
                    // 生成javaBean
                    this.generateModelFile(basePath + "/common/entity/", resultSet, tableName, String.valueOf(tablesComment.get(tableName)), primaryKeyslist);
                    break;
                // 服务模块
                case "service":
                    // 生成service接口
                    this.generateServiceInterfaceFile(basePath + "/service/", resultSet, tableName, String.valueOf(tablesComment.get(tableName)));
                    // 生成service接口实现类
                    this.generateServiceImplFile(basePath + "/service/impl/", resultSet, tableName, String.valueOf(tablesComment.get(tableName)));
                    break;
                // web模块
                case "web":
                    // 生成Controller
                    this.generateControllerFile(basePath + "/web/controller/", resultSet, tableName, String.valueOf(tablesComment.get(tableName)));
                    break;
            }


        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // 关闭数据库连接
            MySQLTableComment.close();
        }
    }

    /**
     * 生成javaBean
     *
     * @throws Exception
     */
    private void generateModelFile(String createProjectPath, ResultSet resultSet, String tableName, String tableAnnotation, List<String> primaryKeyslist) throws Exception {

        final String suffix = ".java";

        final String path = createProjectPath + this.replaceUnderLineAndUpperCase(tableName) + suffix;
        final String templateName = "Entity.ftl";
        File mapperFile = new File(path);
        List<ColumnClass> columnClassList = new ArrayList();
        ColumnClass columnClass = null;
        while (resultSet.next()) {
            columnClass = new ColumnClass();
            String columnName = resultSet.getString("COLUMN_NAME").toLowerCase();
            // 获取字段名称
            columnClass.setColumnName(columnName);
            // 获取字段类型
            columnClass.setColumnType(ColumnType.getJavaTypeOf(resultSet.getString("TYPE_NAME")));
            // 转换字段名称，如 sys_name 变成 SysName
            columnClass.setChangeColumnName(replaceUnderLineAndUpperCase(columnName));
            // 字段在数据库的注释
            columnClass.setColumnComment(resultSet.getString("REMARKS"));
            // 判断字段是否是主键 是:true
            columnClass.setPri(primaryKeyslist.contains(columnName));
            columnClassList.add(columnClass);
        }
        Map<String, Object> dataMap = new HashMap();
        dataMap.put("model_column", columnClassList);
        this.generateFileByTemplate(templateName, mapperFile, dataMap, tableName, tableAnnotation);

    }

    /**
     * 生成Controller
     *
     * @param resultSet
     * @throws Exception
     */
    private void generateControllerFile(String createProjectPath, ResultSet resultSet, String tableName, String tableAnnotation) throws Exception {
        final String suffix = "Controller.java";
        final String path = createProjectPath + this.replaceUnderLineAndUpperCase(tableName) + suffix;
        final String templateName = "Controller.ftl";
        File mapperFile = new File(path);
        Map<String, Object> dataMap = new HashMap();
        // 权限名
        dataMap.put("sub_permission", StringUtils.replace(tableName, "_", ":"));
        // 访问路径
        dataMap.put("sub_path", StringUtils.replace(tableName, "_", "/"));

        this.generateFileByTemplate(templateName, mapperFile, dataMap, tableName, tableAnnotation);
    }

    /**
     * 生成service接口实现类
     *
     * @param resultSet
     * @throws Exception
     */
    private void generateServiceImplFile(String createProjectPath, ResultSet resultSet, String tableName, String tableAnnotation) throws Exception {
        final String suffix = "ServiceImpl.java";
        final String path = createProjectPath + this.replaceUnderLineAndUpperCase(tableName) + suffix;
        final String templateName = "ServiceImpl.ftl";
        File mapperFile = new File(path);
        Map<String, Object> dataMap = new HashMap();
        this.generateFileByTemplate(templateName, mapperFile, dataMap, tableName, tableAnnotation);
    }

    /**
     * 生成service接口
     *
     * @param resultSet
     * @throws Exception
     */
    private void generateServiceInterfaceFile(String createProjectPath, ResultSet resultSet, String tableName, String tableAnnotation) throws Exception {
        final String suffix = "Service.java";
        final String path = createProjectPath + this.replaceUnderLineAndUpperCase(tableName) + suffix;
        final String templateName = "ServiceInterface.ftl";
        File mapperFile = new File(path);
        Map<String, Object> dataMap = new HashMap();
        this.generateFileByTemplate(templateName, mapperFile, dataMap, tableName, tableAnnotation);
    }


    /**
     * 生成MybatisPlus的Mapper
     *
     * @param resultSet
     * @throws Exception
     */
    private void generateMapperFile(String createProjectPath, ResultSet resultSet, String tableName, String tableAnnotation) throws Exception {
        final String suffix = "Mapper.java";
        final String path = createProjectPath + this.replaceUnderLineAndUpperCase(tableName) + suffix;
        final String templateName = "Mapper.ftl";
        File mapperFile = new File(path);
        Map<String, Object> dataMap = new HashMap();
        this.generateFileByTemplate(templateName, mapperFile, dataMap, tableName, tableAnnotation);

    }

    /**
     * 生成数据库字段文件
     */
    private void generateDBDictFile(Map<String, Object> dataMap, DataDictParam dataDictParam) throws Exception {

        // 生成文件名 如果不设置使用数据库名
        String fileName = dataDictParam.getCreateFileName();
        if (StringUtils.isBlank(fileName)) {
            fileName = dataDictParam.getDBName() + "数据字典.md";
        }
        // 使用设置的
        fileName = fileName + ".md";

        // 生成路径
        String basePath = new File("").getCanonicalPath();
        File pathFile = new File(basePath + "/doc/");


        // 判断路径否存在 不存在新建
        if (!pathFile.exists()) {
            pathFile.mkdirs();
        }

        // 利用freemarker 生成文件
        Template template = FreeMarkerTemplateUtils.getTemplate("DataDict.ftl");
        FileOutputStream fos = new FileOutputStream(new File(basePath + "/doc/" + fileName));
        Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"), 10240);
        template.process(dataMap, out);
    }


    /**
     * 利用freemarker模本生成代码
     *
     * @param templateName
     * @param file
     * @param dataMap
     * @param tableName
     * @param tableAnnotation
     * @throws Exception
     */
    private void generateFileByTemplate(
            final String templateName,
            File file,
            Map<String, Object> dataMap,
            String tableName,
            String tableAnnotation
    ) throws Exception {
        Template template = FreeMarkerTemplateUtils.getTemplate(templateName);
        if (file.exists()) {
            System.err.println(file.getName() + "已存在!");
            return;
        }
        FileOutputStream fos = new FileOutputStream(file);
        dataMap.put("table_name_small", tableName);
        dataMap.put("table_name", this.replaceUnderLineAndUpperCase(tableName));
        dataMap.put("db_table_name", tableName);
        dataMap.put("author", CreateCodeParam.AUTHOR);
        dataMap.put("date", CreateCodeParam.CURRENT_DATE);
        dataMap.put("package_name", CreateCodeParam.PACKAGE_NAME);
        dataMap.put("table_annotation", tableAnnotation);
        Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"), 10240);
        template.process(dataMap, out);
    }

    /**
     * 下划线转驼峰
     *
     * @param str
     * @return
     */
    public String replaceUnderLineAndUpperCase(String str) {
        StringBuffer sb = new StringBuffer();
        sb.append(str);
        int count = sb.indexOf("_");
        while (count != 0) {
            int num = sb.indexOf("_", count);
            count = num + 1;
            if (num != -1) {
                char ss = sb.charAt(count);
                char ia = (char) (ss - 32);
                sb.replace(count, count + 1, ia + "");
            }
        }
        String result = sb.toString().replaceAll("_", "");
        return StringUtils.capitalize(result);
    }


    /**
     * 生成链接数据库的url
     *
     * @param ip
     * @return
     */
    public static String createDBLink(String ip) {

        String replace = StringUtils.replace(ip, "\\", "/");
        if (replace.endsWith("/")) {
            replace = StringUtils.substring(replace, 0, replace.length() - 1);
        }
        String url = "jdbc:mysql://" + replace + "?serverTimezone=GMT%2B8&useSSL=false&useOldAliasMetadataBehavior=true&useUnicode=true&characterEncoding=utf8";
        return url;

    }


}
